home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / appletalk / uab.shar / ethertalk.c < prev    next >
C/C++ Source or Header  |  1990-07-12  |  13KB  |  497 lines

  1. static char rcsid[] = "$Author: cck $ $Date: 88/09/14 10:19:26 $";
  2. static char rcsident[] = "$Header: /src/local/mac/cap/etalk/RCS/ethertalk.c,v 1.16 88/09/14 10:19:26 cck Rel $";
  3. static char revision[] = "$Revision: 1.16 $";
  4.  
  5. /*
  6.  * ethertalk.c - ethertalk interface
  7.  *
  8.  *
  9.  * Copyright (c) 1988 by The Trustees of Columbia University 
  10.  *  in the City of New York.
  11.  *
  12.  * Permission is granted to any individual or institution to use,
  13.  * copy, or redistribute this software so long as it is not sold for
  14.  * profit, provided that this notice and the original copyright
  15.  * notices are retained.  Columbia University nor the author make no
  16.  * representations about the suitability of this software for any
  17.  * purpose.  It is provided "as is" without express or implied
  18.  * warranty.
  19.  *
  20.  *
  21.  * Edit History:
  22.  *
  23.  *  April 3, 1988  CCKim Created
  24.  *
  25. */
  26.  
  27. static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
  28. Columbia University in the City of New York";
  29.  
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. #include <sys/types.h>
  33. #include <sys/socket.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/uio.h>
  36. #include <sys/time.h>
  37. #include <net/if.h>
  38. #include <netinet/in.h>
  39.  
  40. #include <netat/appletalk.h>
  41.  
  42. #include "proto_intf.h"        /* iso: level 0 */
  43. #include "ethertalk.h"        /* iso: level 1 */
  44. #include "aarp.h"        /* iso: level 1 */
  45.  
  46. #include "if_desc.h"        /* describes "if" */
  47. #include "ddpport.h"        /* describes a ddp port to "lap" */
  48. #include "log.h"
  49.  
  50. /* some logging ideas */
  51. #define LOG_LOG 0
  52. #define LOG_PRIMARY 1
  53. #define LOG_LOTS 9
  54.  
  55. /*
  56.    Ethertalk packet format:
  57.    :: destination node ::
  58.    :: source node ::
  59.    <data>
  60.  
  61. */
  62.  
  63. private int etalk_init();
  64. private int etalk_getnode();    /* basis */
  65. private etalk_initfinish();
  66.  
  67. private int etalk_send_ddp();
  68. private int etalk_listener();
  69. private NODE *etalk_ddpnode_to_node();
  70. private int etalk_stats();
  71. private int etalk_tables();
  72.  
  73. /* describe our interface to the world */
  74. private char *ethertalk_lap_keywords[] = {
  75.   "ethertalk",
  76.   "elap",
  77.   NULL
  78.  };
  79.  
  80. export struct lap_description ethertalk_lap_description = {
  81.   "EtherTalk Link Access Protocol",
  82.   ethertalk_lap_keywords,
  83.   TRUE,                /* need more than just key */
  84.   etalk_init,            /* init routine */
  85.   etalk_stats,            /* stats routine */
  86.   etalk_tables            /* tables */
  87. };
  88.  
  89.  
  90. /* interface statistics */
  91.  
  92. private char *estat_names[] = {
  93. #define ES_PKT_INPUT  0        /* packets input */
  94.   "packets input",
  95. #define ES_PKT_ACCEPTED    1    /* accepted input packets */
  96.   "packets accepted",
  97. #define ES_PKT_BAD 2        /* bad packets */
  98.   "bad packets",
  99. #define ES_PKT_NOTFORME 3    /* not for me packets */
  100.   "packets not for me",
  101. #define ES_BYTES_INPUT 4    /* accepted bytes */
  102.   "bytes input",
  103. #define ES_ERR_INPUT 5         /* number of input errors */
  104.   "input errors",
  105. #define ES_PKT_NOHANDLER 6    /* no handler */
  106.   "packets without handlers",
  107. #define ES_PKT_OUTPUT  7    /* packets output */
  108.   "packets output",
  109. #define ES_BYTES_OUTPUT 8    /* bytes output */
  110.   "bytes output",
  111. #define ES_ERR_OUTPUT 9        /* output errors */
  112.   "output errors",
  113. #define ES_RESOLVE_ERR_OUTPUT 10 /* could not resolvve */
  114.   "output resolve error"
  115. #define ES_NUM_COUNTERS 11
  116. };
  117.  
  118. typedef struct ethertalk_handle {
  119.   int eh_state;            /* this connection state */
  120. #define ELAP_WAITING -1
  121. #define ELAP_BAD 0        /* error */
  122. #define ELAP_READY 1        /* okay */
  123.   PORT_T eh_port;        /* ethertalk port */
  124.   int eh_ph;            /* ethertalk protocol handle */
  125.   caddr_t eh_ah;        /* aarp module handle */
  126.   NODE eh_enode;        /* host node id */
  127.   IDESC_TYPE *eh_id;        /* interface description */
  128.   int eh_stats[ES_NUM_COUNTERS]; /* statistics */
  129. } E_HANDLE;
  130.  
  131.  
  132. /*
  133.  * call with provisional network number, interface name and number
  134.  *
  135.  * provisional number should be 0 if not seeding
  136.  *
  137. */
  138. private int
  139. etalk_init(id, async)
  140. IDESC_TYPE *id;
  141. int async;
  142. {
  143.   int etph;
  144.   E_HANDLE *eh;
  145.   int hostid;
  146.  
  147.  
  148.   if ((eh = (E_HANDLE *)malloc(sizeof(E_HANDLE))) == NULL)
  149.     return(NULL);
  150.  
  151.   pi_setup();
  152.  
  153.   if ((etph = pi_open(ETHERTYPE_APPLETALK, id->id_intf, id->id_intfno)) < 0) {
  154.     log(LOG_LOG|L_UERR,"pi_open");
  155.     free(eh);
  156.     return(NULL);
  157.   }
  158.   eh->eh_ph = etph;
  159.  
  160.   /* init for a single node */
  161.   eh->eh_ah = (caddr_t)aarp_init(id->id_intf, id->id_intfno, 1);
  162.   if (eh->eh_ah == NULL) {
  163.     log(LOG_LOG|L_UERR, "aarp_init");
  164.     pi_close(etph);
  165.     free(eh);
  166.     return(NULL);
  167.   }
  168.   /* link in both directions */
  169.   id->id_ifuse = (caddr_t)eh;    /* mark */
  170.   eh->eh_id = id;        /* remember this */
  171.  
  172.   eh->eh_state = ELAP_WAITING;    /* mark waiting */
  173.  
  174.   /* acquire node address */
  175.   hostid = 0xff & gethostid();    /* use last byte of hostid as hint */
  176.   if (etalk_getnode(eh, hostid, etalk_initfinish) < 0) {
  177.     pi_close(etph);
  178.     free(eh);
  179.   }
  180.  
  181.   if (async)            /* async means to stop early */
  182.     return(TRUE);
  183.   /* wait for node acquisition? */
  184.   while (eh->eh_state == ELAP_WAITING)
  185.     abSleep(10, TRUE);
  186.   return(eh->eh_state == ELAP_READY); /* true if okay, 0 o.w. */
  187. }
  188.  
  189. /*
  190.  * try to acquire an ethertalk host node address using hint as the basis
  191.  *  callback to who (cbarg is E_HANDLE, result where -1 if address in use
  192.  *  host node address index o.w.)
  193.  *
  194. */
  195. private int
  196. etalk_getnode(eh, hint, who)
  197. E_HANDLE *eh;
  198. int hint;
  199. int (*who)();
  200. {
  201.   struct ethertalkaddr pa;
  202.   int n;
  203.  
  204.   pa.dummy[0] = pa.dummy[1] = pa.dummy[2] = 0;
  205.   /* EtherTalk II fixup */
  206.   pa.node = hint;        /* use fourth byte of eaddr as guess */
  207.   while ((n=aarp_acquire_etalk_node(eh->eh_ah, &pa, who, eh)) != 0) {
  208.     if (n < 0) {
  209.       /* error */
  210.       /* clean up */
  211.       return(-1);
  212.     }
  213.     pa.node++;            /* try next */
  214.   }
  215.   return(0);
  216. }
  217.  
  218. /*
  219.  * finish off the init
  220.  *
  221. */
  222. private
  223. etalk_initfinish(eh, result)
  224. E_HANDLE *eh;
  225. int result;
  226. {
  227.   PORT_T eh_port;        /* ethertalk port */
  228.   struct ethertalkaddr pa;
  229.   int flags;
  230.   int nodesize;
  231.   IDESC_TYPE *id = eh->eh_id;    /* get interface description */
  232.  
  233.   if (result < 0) {
  234.     if ((result = etalk_getnode(eh,(rand()%254)+1, etalk_initfinish)) < 0) {
  235.       log(LOG_LOG, "could not acquire node on interface %s%d\n",
  236.       id->id_intf, id->id_intfno);
  237.       eh->eh_state = ELAP_BAD;
  238.     }
  239.     return;
  240.   }
  241.  
  242.   if ((nodesize = aarp_get_host_addr(eh->eh_ah, &pa, result)) < 0) { 
  243.     log(LOG_PRIMARY, "aarp get host node address failed for %d", result);
  244.     log(LOG_PRIMARY, "interface %s%d can't be intialized",
  245.     id->id_intf, id->id_intfno);
  246.     eh->eh_state = ELAP_BAD;    /* mark bad */
  247.     return;
  248.   }
  249.   eh->eh_enode.n_size = 8*nodesize; /* 8 bits */
  250.   eh->eh_enode.n_bytes = nodesize; /* 1 byte */
  251.   /* EtherTalk II fixup */
  252.   eh->eh_enode.n_id[0] = pa.node; /* this is it */
  253.  
  254.   flags = PORT_WANTSLONGDDP;
  255.   if (!pi_delivers_self_broadcasts())
  256.     flags |= PORT_NEEDSBROADCAST;
  257.   if (id->id_isabridge)
  258.     flags |= PORT_FULLRTMP;
  259.  
  260.   /* establish port */
  261.   /* EtherTalk II fixup */
  262.   eh_port = port_create(id->id_network, pa.node, id->id_zone,
  263.             &eh->eh_enode, flags, (caddr_t)eh,
  264.             etalk_send_ddp, /* send interface */
  265.             etalk_ddpnode_to_node, /* map from ddp */
  266.             NULL,    /* map node to ddp node, net */
  267.             id->id_local);    /* demuxer */
  268.   if (eh_port) {
  269.     /* go to ethertalk level */
  270.     pi_listener(eh->eh_ph, etalk_listener, (caddr_t)eh_port);
  271.     eh->eh_state = ELAP_READY;
  272.     log(LOG_PRIMARY, "port %d acquired node %d on interface %s%d",
  273.     eh_port, pa.node, id->id_intf, id->id_intfno);
  274.   } else {
  275.     eh->eh_state = ELAP_BAD;
  276.    log(LOG_PRIMARY,"acquired node %d on interface %s%d, but no space for port",
  277.     pa.node, id->id_intf, id->id_intfno);
  278.   }
  279.   /* phew */
  280. }
  281.  
  282. /*
  283.  * listen to incoming ethertalk packets and handle them 
  284.  *
  285. */
  286. /*ARGSUSED*/
  287. private
  288. etalk_listener(fd, port, etph)
  289. int fd;                /* dummy */
  290. PORT_T port;
  291. int etph;
  292. {
  293.   static LAP lap;
  294.   /* room for packet and then some */
  295.   static byte rbuf[ddpMaxData+ddpSize+lapSize+100];
  296.   int cc;
  297.   struct iovec iov[3];
  298.   struct ethertalkaddr spa;
  299.   struct ethernet_addresses ea;
  300.   struct ethertalk_handle *eh = PORT_GETLOCAL(port, struct ethertalk_handle *);
  301.   int *stats = eh->eh_stats;
  302.   int ddpnode;
  303.  
  304.   iov[0].iov_base = (caddr_t)&ea;
  305.   iov[0].iov_len = sizeof(ea);
  306.   iov[1].iov_base = (caddr_t)⪅
  307.   iov[1].iov_len = sizeof(lap);
  308.   iov[2].iov_base = (caddr_t)rbuf;
  309.   iov[2].iov_len = sizeof(rbuf);
  310.   if ((cc = pi_readv(etph, iov, 3)) < 0) {
  311.     log(LOG_LOG|L_UERR, "pi_readv: ethertalk_listener");
  312.     stats[ES_ERR_INPUT]++;        /* input error */
  313.     return(cc);
  314.   }
  315.   /* eat the packet and drop it */
  316.   if (eh->eh_state != ELAP_READY) /* drop */
  317.     return(cc);
  318.   /* handle packet */
  319.   cc -= (lapSize+sizeof(ea));
  320.  
  321.   if (lap.src == 0xff) {        /* bad, bad, bad */
  322.     stats[ES_PKT_BAD]++;
  323.     return(-1);
  324.   }
  325.   /* lap dest isn't right */
  326.   /* fixup point */
  327.   ddpnode = PORT_DDPNODE(port);
  328.   if (lap.dst != 0xff && lap.dst != ddpnode) {
  329.     stats[ES_PKT_NOTFORME]++;
  330.     return(-1);
  331.   }
  332.  
  333.   stats[ES_PKT_INPUT]++;
  334.   stats[ES_BYTES_INPUT] += cc;
  335.   /* pick out source for aarp table management if not self */
  336.   /* EtherTalk II fixup */
  337.   if (lap.src != ddpnode) {
  338.     spa.dummy[0] = spa.dummy[1] = spa.dummy[2] = 0;
  339.     spa.node = lap.src;
  340.     if (!aarp_insert(eh->eh_ah, ea.saddr, &spa, FALSE)) /* drop it */
  341.       return(-1);        /* enet address change */
  342.   }
  343.   
  344.   switch (lap.type) {
  345.   case lapDDP:
  346.     ddp_route(port, rbuf, rbuf+ddpSize, cc, lap.dst == 0xff);
  347.     break;
  348.   case lapShortDDP:        /* don't allow short ddp for now */
  349.     /*munge short ddp to ddp */
  350.     sddp_route(port, lap.src, rbuf, rbuf+ddpSSize, cc);
  351.     break;
  352.   default:
  353.     stats[ES_PKT_NOHANDLER]++;
  354.     return(-1);
  355.   }
  356.   return(0);
  357. }
  358.  
  359. /*
  360.  * resolve a ddp node number to a node address on the specified port
  361.  * (note: do we need more information in some cases?)
  362. */
  363. private NODE *
  364. etalk_ddpnode_to_node(port, ddpnet, ddpnode)
  365. PORT_T port;
  366. word ddpnet;
  367. byte ddpnode;
  368. {
  369.   /* EtherTalk II fixup */
  370.   /* think this is okay */
  371.   static NODE node = { 1, 8 }; /* initialize */
  372.   int myddpnet = PORT_DDPNET(port);
  373.  
  374.   if (ddpnet != 0 && myddpnet != ddpnet) /* only allow this net! */
  375.     return(NULL);
  376.   node.n_id[0] = ddpnode;    /* make node */
  377.   return(&node);
  378. }
  379.  
  380. /* resolve a node to a ddp node (do we want this?) */
  381. /* think we will need it + one that resolves it to a net in the future ? */
  382. private byte
  383. etalk_node_to_ddpnode(port, node)
  384. PORT_T port;
  385. NODE *node;
  386. {
  387.   /* EtherTalk II fixup */
  388.   if (node->n_size == 8)    /* 8 bits? */
  389.     return(node->n_id[0]);
  390.   return(0);
  391. }
  392.  
  393.  
  394. /*
  395.  * send a ddp packet on ethertalk
  396.  * (should we convert short to long ddp?)
  397.  * 
  398.  * port = port to send on
  399.  * dstnode == destination ethertalk node
  400.  * laptype == laptype of packet (header)
  401.  * header = packet header (for laptype)
  402.  * hsize = packet header length
  403.  * data = data
  404.  * dlen = datalength
  405. */
  406. private
  407. etalk_send_ddp(port, dstnode, laptype, header, hsize, data, dlen)
  408. PORT_T port;
  409. NODE *dstnode;
  410. int laptype;
  411. byte *header;
  412. int hsize;
  413. u_char *data;
  414. int dlen;
  415. {
  416.   struct iovec iov[3];
  417.   u_char *eaddr;
  418.   LAP lap;
  419.   struct ethertalk_handle *eh = PORT_GETLOCAL(port, struct ethertalk_handle *);
  420.   struct ethertalkaddr tpa;
  421.   int *stats = eh->eh_stats;
  422.   int i;
  423.  
  424.   if (eh->eh_state != ELAP_READY) { /* drop */
  425.     stats[ES_ERR_OUTPUT]++;
  426.     return(-1);
  427.   }
  428.   if (dstnode == NULL) {    /* can't! */
  429.     stats[ES_ERR_OUTPUT]++;        /* can't */
  430.     return(-1);
  431.   }
  432.  
  433.   /* should be higher? */
  434.   if (dstnode->n_size != eh->eh_enode.n_size) { /* for now? */
  435.     stats[ES_ERR_OUTPUT]++;        /* can't */
  436.     return(-1);
  437.   }
  438.   /* source is always us! */
  439.   lap.src = eh->eh_enode.n_id[0]; /* get source node */
  440.   lap.dst = dstnode->n_id[0];    /* get dest node */
  441.   lap.type = laptype;
  442.   /* EtherTalk II fixup */
  443.   tpa.dummy[0] = tpa.dummy[1] = tpa.dummy[2] = 0;
  444.   tpa.node = dstnode->n_id[0];
  445.  
  446.   if (aarp_resolve(eh->eh_ah, &tpa, lap.dst == 0xff, &eaddr) <= 0) {
  447.     stats[ES_RESOLVE_ERR_OUTPUT]++;
  448.     return(-1);
  449.   }
  450.   iov[0].iov_len = lapSize;
  451.   iov[0].iov_base = (caddr_t)⪅
  452.   iov[1].iov_len = hsize;
  453.   iov[1].iov_base = (caddr_t)header;
  454.   iov[2].iov_len = dlen;
  455.   iov[2].iov_base = (caddr_t)data;
  456.   if ((i = pi_writev(eh->eh_ph, iov, (dlen == 0) ? 2 : 3, eaddr)) < 0) {
  457.     stats[ES_ERR_OUTPUT]++;
  458.     return(i);
  459.   }
  460.   stats[ES_PKT_OUTPUT]++;
  461.   stats[ES_BYTES_OUTPUT] += i;
  462.   return(i);
  463. }
  464.  
  465.  
  466. private int
  467. etalk_stats(fd, id)
  468. FILE *fd;
  469. IDESC_TYPE *id;
  470. {
  471.   E_HANDLE *eh = (E_HANDLE *)id->id_ifuse; /* get handle */
  472.   int i;
  473.   
  474.   fprintf(fd, "Interface %s%d statisitics\n", id->id_intf,
  475.       id->id_intfno);
  476.   fprintf(fd, " Interface counters\n");
  477.   for (i = 0; i < ES_NUM_COUNTERS; i++) {
  478.     fprintf(fd, "  %8d\t%s\n", eh->eh_stats[i], estat_names[i]);
  479.   }
  480.   putc('\n', fd);        /* carriage return */
  481.   /* call up aarp too */
  482.   aarp_dump_stats(fd, eh->eh_ah);
  483.   putc('\n', fd);        /* finish */
  484. }
  485.  
  486. private int
  487. etalk_tables(fd, id)
  488. FILE *fd;
  489. IDESC_TYPE *id;
  490. {
  491.   E_HANDLE *eh = (E_HANDLE *)id->id_ifuse; /* get handle */
  492.  
  493.   fprintf(fd, "Interface dump for %s%d\n",id->id_intf, id->id_intfno);
  494.   aarp_dump_tables(fd, eh->eh_ah);
  495.   putc('\n', fd);
  496. }
  497.